Empirical Asset Pricing - PS6

Maximilian Huber

Task 1

In [1]:
# load the data↔

Preliminaries

I observed that the price of options on the day that they expire is odd. If one bought or sold options on the day of their expiry one could frequently make profits:

In [2]:
# find arbitrage opportunities (buy an option and exercise it, or sell an option and fulfill it)↔
Out[2]:
1997-01-01 2002-01-01 2007-01-01 2012-01-01 0 25 50 75 100 125 Number of profitable arbitrage opportunities
In [3]:
# plot histogram of Dollar profits↔
Out[3]:
0 1 2 3 4 5 0 250 500 750 1000 Histogram of profits $ profit

I conclude that I will never want to use the price of an option on the day of its expiry. Hence, in (b) I choose a minimal duration to be a few days longer than the desired holding period.

Writing Straddles

On every day for which there is options data available I sell one ATM call and and one ATM put and receive the best_bid price. I then look up the best_offer price of the respective options via optionid on the first day after the holding period ends.

I use two different schemes to select the options that are sold, and then bought back in a month:

  • a scheme that focuses on achieving at-the-money
  • a scheme that focuses on achieving time-to-maturity

Note: The way the return is calculated is very important!

At first, I calculate returns as if the investor did not have to adhere to margin requirements. That is, there is no necessary deposit at a margin account. Hence, the formula for the return is:

$$R^\text{naive}_{t,t+1} = \frac{P^{\text{call}, i}_t + P^{\text{put}, j}_t}{P^{\text{call}, i}_{t+1} + P^{\text{put}, j}_{t+1}} - 1$$

Then, at the end of (b), (c), and (d) I report returns for a strategy where the margin account needs to have a balance of $M_t = \Big(P^{\text{call}, i}_t + P^{\text{put}, j}_t\Big)\Big(\frac{1}{1-0.8} - 1\Big)$. That is, the the balance on the margin account plus the proceeds from selling the options needs to be enough to cover five times the the current option price. This is motivated by the maximal observed loss of the strategy of $-0.7946$. The return is then:

$$R^\text{margin}_{t,t+1} = \frac{P^{\text{call}, i}_t + P^{\text{put}, j}_t - P^{\text{call}, i}_{t+1} - P^{\text{put}, j}_{t+1}}{M_t} + R^\text{risk free}_t$$

In [4]:
function ATM_focused_scheme(options, trading_dates; last_day = Date(2016, 3, 31), min_days = 33)
end
Out[4]:
ATM_focused_scheme (generic function with 1 method)
In [5]:
function TTM_focused_scheme(options, trading_dates; last_day = Date(2016, 3, 31), min_days = 33)
end
Out[5]:
TTM_focused_scheme (generic function with 1 method)

(b)

Evaluation of the Strategy

I evaluate both schemes:

In [6]:
returns_atm = ATM_focused_scheme(options, trading_dates);
returns_ttm = TTM_focused_scheme(options, trading_dates);
WARNING: No sell data at 1445 2001-09-28 2001-10-29 for 20482729 20482730
WARNING: No sell data at 1446 2001-10-01 2001-10-30 for 20482729 20482730
WARNING: No sell data at 3020 2008-01-02 2008-01-31 for 32962898 32962906
WARNING: Had to increase time-to-maturity because not enough contracts at 1999-06-30

There are not many errors keeping in mind that I evaluate the strategy for every day.

The ATM-focused scheme is more concentrated around the zero percent deviation from ATM, while the TTM-focused scheme has shorter time-to-maturity. The holding periods are equal. And the two scheme regularly select different options:

In [7]:
# plots to assess how well the strategy is fulfilled↔
Out[7]:
-1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 0 100 200 300 400 500 Histrogram of Moneyness % deviation from ATM 50 100 150 200 250 300 0 500 1000 1500 Histrogram of Time to Maturity days ATM focused TTM focused 29 30 31 32 33 34 35 0 1000 2000 3000 Histrogram of Holding Period days 1997-01-01 2002-01-01 2007-01-01 2012-01-01 0.4 0.6 0.8 1.0 Average Agreement of the two Schemes call put

I execute the trading strategy on the end of every month. The two schemes perform very similarly:

In [8]:
# plot the performance↔
Out[8]:
1997-01-01 2002-01-01 2007-01-01 2012-01-01 5 10 15 20 25 30 35 Log Cumulative Returns ATM focused TTM focused 1997-01-01 2002-01-01 2007-01-01 2012-01-01 -0.5 0.0 0.5 1.0 1.5 Returns

Returns with a Conservative Margin Requirement

The returns of the ATM-focused scheme with a four-fold margin requirement are much more realistic:

In [9]:
# plot the performance↔
Out[9]:
1997-01-01 2002-01-01 2007-01-01 2012-01-01 0 1 2 3 Log Cumulative Returns 1997-01-01 2002-01-01 2007-01-01 2012-01-01 -0.5 0.0 0.5 1.0 Returns

(c)

In [10]:
returns_atm1y = ATM_focused_scheme(options, trading_dates, last_day = Date(2015, 3, 31), min_days = 368)
returns_ttm1y = TTM_focused_scheme(options, trading_dates, last_day = Date(2015, 3, 31), min_days = 368);
WARNING: No sell data at 946 1999-10-01 2000-09-29 for 11906044 11906045
WARNING: No sell data at 2789 2007-02-01 2008-01-31 for 32223514 32223515
WARNING: Had to increase time-to-maturity because not enough contracts at 1999-03-31
WARNING: Had to increase time-to-maturity because not enough contracts at 1999-03-31
WARNING: Had to increase time-to-maturity because not enough contracts at 1999-03-31
WARNING: Had to increase time-to-maturity because not enough contracts at 1999-03-31
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-09
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-12
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-13
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-14
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-15
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-16
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-21
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-22
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-23
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-26
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-27
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-28
WARNING: Had to increase time-to-maturity because not enough contracts at 2007-03-29

There are some more instances where there is no price at the desired buy-back date and quite a few times there are not enough contracts traded on a sell day.

Again, the ATM-focused scheme yields lower deviation from ATM, while the TTM-focused scheme has no time-to-maturity outliers but has moneyness outliers. The strategies agree quite often, but with episodes of significant deviation:

In [11]:
# plots to assess how well the strategy is fulfilled↔
Out[11]:
-10 -5 0 5 10 15 0 100 200 300 400 Histrogram of Moneyness % deviation from ATM 400 500 600 700 800 900 0 100 200 300 Histrogram of Time to Maturity days ATM focused TTM focused 364 365 366 367 368 369 370 0 1000 2000 3000 4000 Histrogram of Holding Period days 1997-01-01 2002-01-01 2007-01-01 2012-01-01 0.0 0.2 0.4 0.6 0.8 1.0 Average Agreement of the two Schemes call put

If I chose to execute the strategy on the last trading date of every year, the performance would be:

In [12]:
# plot the performance↔
Out[12]:
1997-01-01 2002-01-01 2007-01-01 2012-01-01 -1 0 1 2 3 Log Cumulative Returns ATM focused TTM focused 1997-01-01 2002-01-01 2007-01-01 2012-01-01 0 2 4 6 Returns high frequency returns

Let me compare annual returns, that is I report the returns from the monthly strategy started on any given day and repeated 11 times in the following year.

In [13]:
# plot the histogram of annualized returns↔
Out[13]:
0 500 1000 1500 2000 2500 0 100 200 300 400 Annual Returns by Holding Period % return one month one year

This histogram suggests that the short-term volatility selling strategy is better than the long-term strategy.

Returns with a Conservative Margin Requirement

In [14]:
# plot the performance↔
Out[14]:
1997-01-01 2002-01-01 2007-01-01 2012-01-01 -0.5 -0.4 -0.3 -0.2 -0.1 Log Cumulative Returns 1997-01-01 2002-01-01 2007-01-01 2012-01-01 -0.4 -0.2 0.0 0.2 Returns high frequency returns

There is no money to be made selling long-term volatility!

In [15]:
# plot the histogram of annualized returns↔
Out[15]:
-100 0 100 200 0 100 200 300 400 Annual Returns by Holding Period % return one month one year

(d)

In [16]:
# load risk free rate↔

I use the ATM-focused excess returns and calculate point estimates. The monthly returns are aggregate to yearly returns:

In [17]:
returns1m = ([prod([returns_atm[searchsortedlast(returns_atm[:date], d + Dates.Month(m)), :return] for m in 0:11] .+ 1) - 1 for d in returns_atm[:date][1:4843]]+1) ./ ([interest[searchsortedlast(interest[:date], d), :RF] for d in returns_atm[1:4843, :date]]/100 + 1) .- 1
returns1y = ((returns_atm1y[:return]+1) ./ ([interest[searchsortedlast(interest[:date], d), :RF] for d in returns_atm1y[:date]]/100 + 1) .- 1)[1:4843];
In [18]:
# point estimates with standard functions↔
Out[18]:
StatisticStrategy_1mStrategy_1y
1Mean12.20060.191947
2Std. Dev.37.90060.695596
3Sharpe Ratio0.3219110.275946

But I need an approximate distribution, so I do joint GMM (i.e. both the monthly and yearly strategy in one estimation, this turns out not to be relevant) with the following moment function, where $\theta_1 = \mu_{1m}$, $\theta_2 = \sigma_{1m}$, $\theta_1 = \mu_{1y}$ and $\theta_2 = \sigma_{1y}$:

In [48]:
#operates on a single observation, w[1] = return_1m, w[2] = return_1y
function g(w, θ)
    [w[1] - θ[1], (w[1] - θ[1])^2 - θ[2]^2, w[2] - θ[3], (w[2] - θ[3])^2 - θ[4]^2]
end
Out[48]:
g (generic function with 1 method)
In [49]:
# my standard GMM setup, with Newey-West HAC variance estimation↔
Out[49]:
Γ! (generic function with 1 method)
In [50]:
# standard efficient GMM procedure↔
Out[50]:
eff_GMM (generic function with 1 method)
In [51]:
result = eff_GMM(hcat(returns1m, returns1y), Jn = 30)
Out[51]:
2-element Array{Array{Float64,N} where N,1}:
 [12.2006, 37.8966, 0.191947, 0.695524]                                                                                                                   
 [2.4026 9.18919 0.0295112 0.0416276; 9.18919 44.6641 0.114674 0.210015; 0.0295112 0.114674 0.00222891 0.0023596; 0.0416276 0.210015 0.0023596 0.00546273]

This yields: $$\left[\begin{array}{c} \mu_{1m}\\ \sigma_{1m}\\ \mu_{1y}\\ \sigma_{1y} \end{array}\right]\sim\mathcal{N}\left(\left[\begin{array}{c} 12.2006\\ 37.8966\\ 0.19194\\ 0.69552 \end{array}\right],\left[\begin{array}{cccc} 2.4026 & 9.18919 & 0.029511 & 0.041627\\ 9.18919 & 44.6641 & 0.11467 & 0.210015\\ 0.029511 & 0.11467 & 0.002228 & 0.002359\\ 0.041627 & 0.21005 & 0.002359 & 0.005462 \end{array}\right]\right)$$

Applying the Delta-Method with $f(\theta) = \big[\frac{\theta_1}{\theta_2}, \, \frac{\theta_3}{\theta_4}\big]$:

In [52]:
f(θ) = [θ[1]/θ[2], θ[3]/θ[4]]

SR_result = [f(result[1]), ForwardDiff.jacobian(f, result[1]) * result[2] * ForwardDiff.jacobian(f, result[1])']
Out[52]:
2-element Array{Array{Float64,N} where N,1}:
 [0.321944, 0.275974]                             
 [0.000776475 -8.96187e-6; -8.96187e-6 0.00277534]

That is:

$$\left[\begin{array}{c} SR_{1m}\\ SR_{1y} \end{array}\right]\sim\mathcal{N}\left(\left[\begin{array}{c} 0.32194\\ 0.27597 \end{array}\right],\left[\begin{array}{cc} 0.0007764 & -0.000008\\ -0.000008 & 0.002775 \end{array}\right]\right)$$

Hence, the difference $f(\theta)=\theta_1-\theta_2$:

In [53]:
f(θ) = [θ[1] - θ[2]]

Diff_result = [f(SR_result[1]), ForwardDiff.jacobian(f, SR_result[1]) * SR_result[2] * ForwardDiff.jacobian(f, SR_result[1])']
Out[53]:
2-element Array{Array{Float64,N} where N,1}:
 [0.04597]   
 [0.00356974]

That is:

$$\Delta SR = SR_{1m}-SR_{1y}\sim\mathcal{N}\left(0.04597,\,0.00357\right)$$

The $\mathcal{H}_0$ is that $\Delta SR \leq 0$, the $\mathcal{H}_1$ is that $\Delta SR \gt 0$. The test statistic is $\frac{\mu_{\Delta SR}}{\sigma_{\Delta SR}}$, and the corresponding p-value can be calculated by see how much mass there is below zero:

In [54]:
using Distributions
cdf(Normal(Diff_result[1][1], Diff_result[2][1]), 0.)
Out[54]:
3.0048338873143014e-38

A clear rejection of the $\mathcal{H}_0$!

Results with a Conservative Margin Requirement

In [64]:
# point estimates with standard functions↔
Out[64]:
StatisticStrategy_1mStrategy_1y
1Mean0.159242-0.0178043
2Std. Dev.0.3816150.136739
3Sharpe Ratio0.417283-0.130207
In [65]:
# running GMM and the Delta method again, evalutating the test statistic↔
Out[65]:
0.0

The p-value is again significant! The $\mathcal{H}_0$ is rejected!

Task 2

(a) and (b)

Mind: The return needs to be calculated as changes from close to close price as opposed to changes from open to close. There are frequent, positive jumps between consecutive close and open prices.

In [207]:
# load the data↔

My convention is that the date in the row marks the end-of-period, the return and rf has been achieved inside of this period, but the vrp only became available at the end. Multi-period returns start in the period for with Date is the end-of-month date. Hence in predictive regressions I need to regress next period's return on this period's vrp.

(c)

In [204]:
function OLS(data, sym)
    df = dropmissing(data[[sym, :vrp]])
    Y = convert.(Float64, df[2:end, sym])
    X = hcat(ones(length(Y)), df[1:end-1, :vrp])
    β = round.((X'X) \ (X'Y), 5)
    ϵ = Y - X * β
    σsq = (ϵ' * ϵ) / length(ϵ)
    aVarβ = (X' * X) ./ length(ϵ) .* σsq
    DataFrame(LHS = string(sym), End_Date = data[end, :Date], α = β[1], α_sd = sqrt.(diag(aVarβ) ./ length(ϵ))[1], β = β[2], β_sd = sqrt.(diag(aVarβ) ./ length(ϵ))[2])
end

#tabular(vcat(vec([OLS(data[ran, :], Symbol("ex_return1$p")) for p in ["m", "q", "y"], ran in [1:216, 1:size(data, 1)]])...), rounding=4);

\begin{array}{cccccc} \hline LHS & until & \beta_0 & \sigma(\beta_0) & \beta_1 & \sigma(\beta_1)\\ \hline \text{1m} & 2007 & -0.0002 & 0.0026 & 0.0003 & 0.0637\\ \text{1q} & 2007 & -0.0064 & 0.0044 & 0.0013 & 0.106\\ \text{1y} & 2007 & 0.0323 & 0.0102 & 0.002 & 0.2466\\ \text{1m} & 2017 & -0.0007 & 0.0022 & 0.0004 & 0.0565\\ \text{1q} & 2017 & 0.0017 & 0.0038 & 0.0011 & 0.0984\\ \text{1y} & 2017 & 0.0645 & 0.0088 & 0.0012 & 0.2318 \end{array}

After the financial crisis the predictive power of the variance risk premium is getting weaker using it for longer horizons.

Mind: the reported standard errors are not adjusted for autocorrelation!

(d)

In [206]:
function GLS(data, sym)
    df = dropmissing(data[[sym, :vrp, :vix]])
    Y = convert.(Float64, df[2:end, sym])
    X = hcat(ones(length(Y)), df[1:end-1, :vrp])
    β = round.((X' * diagm(1 ./ df[1:end-1, :vix]) * X) \ (X' * diagm(1 ./ df[1:end-1, :vix]) * Y), 5)
    ϵ = Y - X * β
    σsq = (ϵ' * ϵ) / length(ϵ)
    aVarβ = (X' * X) ./ length(ϵ) .* σsq
    DataFrame(LHS = string(sym), End_Date = data[end, :Date], α = β[1], α_sd = sqrt.(diag(aVarβ) ./ length(ϵ))[1], β = β[2], β_sd = sqrt.(diag(aVarβ) ./ length(ϵ))[2])
end

#tabular(vcat(vec([GLS(data[ran, :], Symbol("ex_return1$p")) for p in ["m", "q", "y"], ran in [1:216, 1:size(data, 1)]])...), rounding=4);

\begin{array}{cccccc} \hline LHS & until & \beta_0 & \sigma(\beta_0) & \beta_1 & \sigma(\beta_1)\\ \hline \text{1m} & 2007 & 0.0018 & 0.0026 & 0.0002 & 0.0638\\ \text{1q} & 2007 & 0.0008 & 0.0044 & 0.001 & 0.1063\\ \text{1y} & 2007 & 0.0478 & 0.0102 & 0.0016 & 0.2472\\ \text{1m} & 2017 & 0.001 & 0.0022 & 0.0004 & 0.0565\\ \text{1q} & 2017 & 0.0053 & 0.0038 & 0.001 & 0.0985\\ \text{1y} & 2017 & 0.0683 & 0.0088 & 0.0012 & 0.2319 \end{array}

Bollerslev et al (2009) define $VRP_t = IV_t - RV_t$ where $RV_t$ is the realized volatility in the period that ended with $t$. $IV_t$ is the implied volatility.

Hence VIX $\approx IV_t$, because the VIX is the implied volatility from one-month options. GLS down-weights exactly those observations where $IV_t$ is high. This decreases the "freak" losses in the financial crisis, when the VIX stayed high for some time.

So the GLS estimation predicts positive returns whenever the VIX is high and the realized volatility is low, but down-weighs observations where VIX is high. In sum, observations with low realized volatility are over-weighted.

This makes sense if I think of the variance risk premium as being paid if the volatility stays low after being low already.